热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

读数|接线_关于NorFlash的一点总结

篇首语:本文由编程笔记#小编为大家整理,主要介绍了关于NorFlash的一点总结相关的知识,希望对你有一定的参考价值。       最近在搞Uboot时才

篇首语:本文由编程笔记#小编为大家整理,主要介绍了关于NorFlash的一点总结相关的知识,希望对你有一定的参考价值。


        最近在搞Uboot时才发现自己的裸机实验中没有相关NorFlash的代码,对NorFlash一无所知,查了一些资料,将自己的一点心得总结一下。

       开发板:mini2440

       NorFlash:SST39VF1601

 

       NorFlash简单来说与sdram与Nand的中间品,它能像sdram一样直接读,但是又得像nand一样编程擦写。因此程序可以直接在nor里跑,速度要比sdram慢一些,往nor里写数据必须先擦除,因为nor的每一位只能由1变为0。Nor可读不可直接写的特性可以被用来判断是Nor启动还是nand启动,因为nand启动的话前4K是可写的,我们写入数据再读取出来应该是没有问题的,而nor启动的话,读出的数据必然是错误的。


NorFlash的硬件接线:

       首先,如果做过sdram实验的朋友应该知道,NorFlash与sdram很相似,只不过sdram位宽为32,NOR为16。在硬件连接上,Nor的地址线与cpu的地址线错开1位,sdram错开2位。简单分析一下:


       32位的CPU地址线为32位,每一个地址对应1个byte,地址的步长为1byte
               0x0000 0000 对应第1个地址空间 大小为1bytes
               0x0000 0001 对应  2           大小为1bytes
               依次类推...
               可以理解为cpu的地址类型 为 u8 * addraddr+1  移动1个字节
       32位的sdram,每一个地址对应于4个byte,地址步长为4byte
               0x0000 0000 对应第1个地址空间 大小为4bytes
               0x0000 0001 对应  2           大小为4bytes
               依次类推...
               可以理解为sdram的地址类型 为 u32 * addraddr+1  移动4个字节
       16位的nor,每一个地址对应于2个byte,地址步长为2byte
               0x0000 0000 对应第1个地址空间 大小为2bytes
               0x0000 0001 对应  2           大小为2bytes
               依次类推...
               可以理解为nor的地址类型 为 u16 * addraddr+1  移动2个字节
       因此,CPU的地址与它们的地址是错位的。
               CPU的4个连续地址 如 0 1 2 3 均对应于sdram的 0地址
               CPU的2个连续地址 如 0 1     均对应于nor  的 0地址

       假如我想取sdram 0地址的 第二个byte 地址如何写?对于sdram和nor具体的每一个byte是无法寻址的呀,但是arm有一个叫存储管理器的东西,它大概会帮我们实现单字节的读写,至于sdram和nor支不支持单字节读写,我们后边在分析。


NorFlash的软件设置:


       需要像初始化sdram一样,设置Bank寄存器,主要是一些时序图的时间大小。

       位宽在BWSCON寄存器中设置,不过它是由硬件决定的,bank0的位宽,我们拨动开关选择nor启动还是nand启动的时候,它就已经确定了。


NorFlash信息:

        我这款Nor大小为2M,32个Block,每个block分为16个sector,一个sector为4K,具体信息如下图。

NorFlash写、擦除、读芯片ID:

       Nor可以像sdram一样直接读取,对于其它的操作,例如写、擦除、读信息等需要写特定的Date到特定的Addr。

这里尤其需要注意的是&#xff0c;Addr指的是nor地址线上看到的地址&#xff0c;相对于cpu也就是我们写程序的时候&#xff0c;需要将addr<<1&#xff0c;这样cpu错位的地址线发出的地址正好对上nor需求的地址。


        对于擦除操作&#xff0c;nor支持按block、sector或者整片的擦除&#xff0c;整个擦除需要6个周期&#xff0c;以按sector擦除为例&#xff0c;前五个周期为往XXX里写XXX&#xff0c;最后一个周期将0X30写入要擦除的sector对应的首地址即可。

        对于写操作&#xff0c;需要4个周期&#xff0c;前3个周期往XXX里写XXX&#xff0c;最后一个周期将Data写入addr&#xff0c;这里需要注意的是addr必须是半字对齐&#xff0c;data也要求为16bit。

       对于读取信息的操作&#xff0c;主要是读ID的操作&#xff0c;前3个周期往XXX里写XXX&#xff0c;第四个周期去读特定的地址&#xff0c;对于DeviceID来说&#xff0c;A1-A19&#61;0,A0&#61;1&#xff0c;对于CPU来说就是0x1<<1.      

NorFlash的等待&#xff1a;
       NorFlash有三种方式&#xff0c;1中读硬件引脚&#xff0c;另外两种读地址线&#xff0c;主要用读地址线的两种方式。
       1、Toggle
             连续读两次相同地址的数据&#xff0c;看DQ6是否相等&#xff0c;相等则擦除或写完成
       2、polling
             读数据&#xff0c;看DQ7是否正确&#xff0c;正确则擦除完成。如果擦除的话DQ7应该等于1&#xff0c;写操作的话&#xff0c;对比数据的第7位。




还有&#xff0c;很重要的一点&#xff1a;

经过我的测试&#xff0c;sdram的单字节读取没有问题&#xff0c;但是Nor单字节读取的时候&#xff0c;读出的数据并不正确。比如我在0x00地址处写入了0xff11&#xff0c;单字节读取0x0理论上应该得到0x11&#xff0c;而我在实际实验的时候得到的却是0xff。也就是说nor在存储半字数据的时候高8位于低8位互换了。



#include "uart.h"
#define MAIN_SECT_SIZE (4*1024) /* 4 KB */
#define CMD_UNLOCK1 0x000000AA
#define CMD_UNLOCK2 0x00000055
#define CMD_ERASE_SETUP 0x00000080
#define CMD_ERASE_CONFIRM 0x00000030
#define CMD_PROGRAM 0x000000A0
#define MEM_FLASH_ADDR1 (*(volatile U16 *)(0x000005555 <<1))
#define MEM_FLASH_ADDR2 (*(volatile U16 *)(0x000002AAA <<1))
#define U16 unsigned short
#define U32 unsigned long
#define U8 unsigned char
int write_hword (U32 dest, U16 data);
typedef struct
U32 size; /* total bank size in bytes */
U16 sector_count; /* number of erase units */
U32 flash_id; /* combined device & manufacturer code */
U32 start[512]; /* physical sector start addresses */
flash_info_t;
/*-----------------------------------------------------------------------*/
void flash_id()
MEM_FLASH_ADDR1 &#61; CMD_UNLOCK1;
MEM_FLASH_ADDR2 &#61; CMD_UNLOCK2;
MEM_FLASH_ADDR1 &#61; 0x00000090;
print("Manufacturer ID :%x\\r\\n",*((U16 *)0x00));
MEM_FLASH_ADDR1 &#61; CMD_UNLOCK1;
MEM_FLASH_ADDR2 &#61; CMD_UNLOCK2;
MEM_FLASH_ADDR1 &#61; 0x00000090;
print("Device ID :%x\\r\\n",*((U16 *)(0x01<<1)));
void flash_init () //计算总大小&#xff0c;每个sector的起始地址
flash_id();
//print("flash init OK\\r\\n");
print("*((U32 *)0x32000000) &#61; 0x00001100\\r\\n");
*((U32 *)0x32000000) &#61; 0x00001100;
print("U8 0x32000001 &#61;&#61; %x\\r\\n",*((U8 *)0x32000001));

*((U8 *)0x32000003) &#61; 0xff;
print("*((U8 *)0x32000003) &#61; 0xff\\r\\n");
print("now the U32 0x32000000 should be 0xff001100\\r\\n");
print("U32 0x32000000 &#61; %x\\r\\n",*((U32 *)0x32000000));
print("U8 0x32000000 &#61; %x\\r\\n",*((U8 *)0x32000000));
print("U8 0x32000001 &#61; %x\\r\\n",*((U8 *)0x32000001));
print("U8 0x32000002 &#61; %x\\r\\n",*((U8 *)0x32000002));
print("U8 0x32000003 &#61; %x\\r\\n",*((U8 *)0x32000003));
if(flash_erase(0,1) &#61;&#61; 0)
print("erase OK\\r\\n");
U32 a &#61; 0x00001c15;
U16 b &#61; 0x11ff;
write_hword(a,b);
print("*(U32 *0x00001c15) &#61;&#61; 0x11ff\\r\\n");
print("U8 0x1c15 &#61; %x\\r\\n",*((U8 *)0x1c15));
print("U8 0x1c16 &#61; %x\\r\\n",*((U8 *)0x1c16));
print("U16 0x1c15 &#61; %x\\r\\n",*((U16 *)0x1c15));

if(write_buff((1024*20),0,(7*1024)) &#61;&#61; 0)
print("write OK\\r\\n");
int flash_erase (int s_first, int s_last)
int i,j;
U32 size &#61; 0;
flash_info_t flash_info;
for (i &#61; 0; i <1; i&#43;&#43;)
U32 flashbase &#61; 0;
flash_info.size &#61; 2*1024*1024;
flash_info.sector_count &#61; 512;
flashbase &#61; 0;

for (j &#61; 0; j flash_info.start[j] &#61;
flashbase &#43; (j) * MAIN_SECT_SIZE;
//print("%d \\t:%d\\r\\n",j,flash_info.start[j]);



int sect;
unsigned short temp;
/* Start erase on unprotected sectors */
for (sect &#61; s_first; sect <&#61; s_last; sect&#43;&#43;)
print ("Erasing sector %d ... \\r\\n", sect&#43;1);
volatile U16 * addr &#61; (volatile U16 *)(flash_info.start[sect]);
MEM_FLASH_ADDR1 &#61; CMD_UNLOCK1;
MEM_FLASH_ADDR2 &#61; CMD_UNLOCK2;
MEM_FLASH_ADDR1 &#61; CMD_ERASE_SETUP;
MEM_FLASH_ADDR1 &#61; CMD_UNLOCK1;
MEM_FLASH_ADDR2 &#61; CMD_UNLOCK2;
*addr &#61; CMD_ERASE_CONFIRM;
print("wait\\r\\n");
while(1)

temp &#61; (*addr) & 0x40; // 0100 0000 DQ6
if(temp !&#61; (*addr) & 0x40) //DQ6
continue;
if(*addr & 0x80) //dq7 &#61;&#61;1
break;


return 0;
//写16位数据&#xff0c;地址应该是16位对齐的。
int write_hword (U32 dest, U16 data)
//print("now to write %d\\r\\n",dest);
int rc;
volatile U16 *addr &#61; (volatile U16 *)dest;
U16 result;
//Check if Flash is (sufficiently) erased
result &#61; *addr;
if ((result & data) !&#61; data)
return 1;
MEM_FLASH_ADDR1 &#61; CMD_UNLOCK1;
MEM_FLASH_ADDR2 &#61; CMD_UNLOCK2;
MEM_FLASH_ADDR1 &#61; CMD_PROGRAM;
*addr &#61; data;
while(1)
unsigned short i &#61; *addr & 0x40;
if(i !&#61; (*addr & 0x40)) //D6 &#61;&#61; D6
continue;
if((*addr & 0x80) &#61;&#61; (data & 0x80))
rc &#61; 0;
break; //D7 &#61;&#61; D7


//print("write %d OK\\r\\n",dest);
return rc;
int write_buff (U32 src, U32 addr, U32 len)
int rc;
U16 data; //16Bit?
if(addr % 2)
print("addr is not for 16bit align\\n");
return 1;

while (len >&#61; 2)
data &#61; *((volatile U16 *) src);
if ((rc &#61; write_hword (addr, data)) !&#61; 0)
return (rc);

src &#43;&#61; 2;
addr &#43;&#61; 2;
len -&#61; 2;

return 0;






推荐阅读
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 深入解析C语言中结构体的内存对齐机制及其优化方法
    为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。 ... [详细]
  • 蒜头君的倒水问题(矩阵快速幂优化)
    蒜头君将两杯热水分别倒入两个杯子中,每杯水的初始量分别为a毫升和b毫升。为了使水冷却,蒜头君采用了一种特殊的方式,即每次将第一杯中的x%的水倒入第二杯,同时将第二杯中的y%的水倒入第一杯。这种操作会重复进行k次,最终求出两杯水中各自的水量。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • STM32串口通信:完整指南
    众所周知,串口通信是MCU最基本的通信方式,对于STM32来说也是如此。本文重点讲述STM32单片机的串口通信,主要包括的内容是:通信基础知识、串口通信原理、USART有关寄存器和 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • C语言中全部可用的数学函数有哪些?2.longlabs(longn);求长整型数的绝对值。3.doublefabs(doublex);求实数的绝对值。4.doublefloor(d ... [详细]
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • Codeforces竞赛解析:Educational Round 84(Div. 2评级),题目A:奇数和问题
    Codeforces竞赛解析:Educational Round 84(Div. 2评级),题目A:奇数和问题 ... [详细]
  • 你的问题在于:1. 代码格式混乱,缺乏必要的缩进,导致可读性极低;2. 使用 `strlen()` 和 `malloc()` 函数时,必须包含相应的头文件;3. `write()` 函数的返回值处理不当,建议检查并处理其返回值以确保程序的健壮性。此外,建议在编写代码时遵循良好的编程规范,增加代码的可维护性和可读性。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
author-avatar
临别一眼_200910
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有